package faceentity;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;


abstract class ServerProcess {
    private int state = 0; // 进程状态 0:未运行 1:运行中
    private Process process;
    public String archiveID;
    public Path exeFilePath;

    public Path workPath;
    BlockingQueue<String> inputLineQ = new ArrayBlockingQueue<>(128);
    // BlockingQueue<String> outputLineQ = new ArrayBlockingQueue<>(128);
    // BlockingQueue<String> errorputLineQ = new ArrayBlockingQueue<>(128);


    public ServerProcess(int state, String archiveID, Path exeFilePath, Path workPath) {
        this.state = state;
        this.archiveID = archiveID;
        this.exeFilePath = exeFilePath;
        this.workPath = workPath;
    }

    public ServerProcess() {
    }

    public void killProcess()
    {
        this.process.destroy(); // 请求进程正常终止
    }

    public void kill9Process()
    {
        this.process.destroyForcibly(); // 强制终止进程
    }

    public void inputLine(String line){

        try {
            this.inputLineQ.put(line);
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
        }
    }

    public long getPID()
    {
        return this.process.pid();
    }

    public int getState()
    {
        if(process != null && process.pid() != 0)
        {
            return 1;
        }
        return 0;
    }


    public abstract void upstateByStdout(String line);

    public abstract void upstateByErrout(String line);

    /**
     * @param args
     * @return
     */
    public int buildProcess(List<String> args) {
        // 创建一个列表，用于存储命令和参数
        List<String> command = new ArrayList<>();
        command.add(exeFilePath.toAbsolutePath().toString()); // 添加可执行文件路径
//        command.add(archiveID);          // 添加 id 参数

        // 将可变参数 args 添加到命令列表中
        if(args != null){
            for (String arg : args) {
                command.add(arg);
            }
        }
        // 使用 ProcessBuilder 创建子进程
        ProcessBuilder processBuilder = new ProcessBuilder(command);
        if (workPath != null){
            processBuilder.directory(new File(workPath.toAbsolutePath().toString()));
        }

        // 启动子进程并处理输出
        try {
            this.process = processBuilder.start();
            System.out.println(this.exeFilePath + " " + archiveID + " Server start...");
            // 创建标准输入线程 以实现控制台功能
            new Thread(() -> {
                try (PrintWriter writer = new PrintWriter(process.getOutputStream(), true)) {
                    while(true) {
                        String line = this.inputLineQ.take();
                        System.out.println(this.exeFilePath + " " + archiveID + " Stdin: " + line);
                        writer.println(line);  
                    }                  
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });

            // 处理标准输出
            new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        System.out.println(this.exeFilePath + " " + archiveID + " Stdout: " + line);
                        this.upstateByStdout(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
            // 处理错误输出
            new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        System.err.println(exeFilePath + " " + archiveID + " Error: " + line);
                        this.upstateByErrout(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
            // 等待进程结束
            int exitCode = process.waitFor();
            return exitCode;
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
        return 1;
    }
}

// private变量只能被upstateByStdout写
public class DSTServerProcess extends ServerProcess {
    private int playerNum = 0;
    private int inited = 0;

    public DSTServerProcess(int state, String archiveID, Path exeFilePath, Path workPath) {
        super(state, archiveID, exeFilePath, workPath);
    }

    public DSTServerProcess() {}

    public int getPlayerNum()
    {
        return playerNum;
    }

    public int getInited()
    {
        if(this.getState() == 0)
        {
            this.inited = 0;
        }
        return inited;
    }

    public boolean updatePlayerNum() {
        try {
            // 发送一条服务器指令
            String line = "print(TheNet:GetNumPlayers())";
            this.inputLineQ.put(line);
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    };

    public boolean shutdown() {
        try {
            String line = "c_shutdown(true)";
            this.inputLineQ.put(line);
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    public void upstateByStdout(String line)
    {
        if(clientConnect(line))
        {
            playerNum++;
        } else if(clientLost(line)){
            playerNum--;
        }
        return ;
    }
    public void upstateByErrout(String line)
    {
        return ;
    }

    private boolean clientConnect(String input)
    {
        String searchString = "Client connected from";

        // 判断字符串是否包含指定内容
        if (input.contains(searchString)) {
            return true;
        } else {
            return false;
        }
    }

    private boolean clientLost(String input)
    {
        String searchString = "Connection lost to";

        // 判断字符串是否包含指定内容
        if (input.contains(searchString)) {
            return true;
        } else {
            return false;
        }
    }

    private void updateInited(String input)
    {
        String searchString = "started on port:";

        // 判断字符串是否包含指定内容
        if (input.contains(searchString)) {
            this.inited = 1;
        }
    }
}